#include "SceneLoader.h"
#include "SceneConfiguration.h"
#include "SceneField.h"
#include <algorithm/rayTracing/rayTracingDataStructure/grid/CudaGrid.cuh>
#include <algorithm/rayTracing/rayTracingDataStructure/grid/CudaRectangleGrid.cuh>
#include <algorithm/rayTracing/rayTracingDataStructure/heliostat/CudaHeliostat.cuh>
#include <algorithm/rayTracing/rayTracingDataStructure/heliostat/CudaRectangleHelio.cuh>
#include <algorithm/rayTracing/rayTracingDataStructure/receiver/CudaCylinderReceiver.cuh>
#include <algorithm/rayTracing/rayTracingDataStructure/receiver/CudaReceiver.cuh>
#include <algorithm/rayTracing/rayTracingDataStructure/receiver/CudaRectangleReceiver.cuh>
#include <algorithm/rayTracing/rayTracingDataStructure/receiver/CudaRefinedCylinderReceiver.cuh>
#include <algorithm/rayTracing/rayTracingDataStructure/receiver/CudaRefinedRectangleReceiver.cuh>
#include <algorithm/rayTracing/rayTracingDataStructure/sunRay/CudaSunRay.cuh>
#include <algorithm/shared/tool/stringHash/StringHash.hpp>

#include <iostream>

using namespace solar;
using namespace solar::cuda;

// void SceneLoader::setFile(std::string json_file_path)
// {
//     json_file_path_ = json_file_path;
// }
void SceneLoader::readFile(std::shared_ptr<SceneConfiguration>& config,
                           std::shared_ptr<SceneField>& field)
{
    std::ifstream ifs(json_file_path_, std::ios_base::in);
    pt::ptree tree;
    pt::read_json(ifs, tree);

    config_ = config;

    // test
    // std::cout << "根节点包含" << tree.size() << "个孩子节点" << std::endl;
    // for (pt::ptree::iterator it = tree.begin(); it != tree.end(); ++it)
    // {
    //     std::cout << it->first << std::endl;
    // }
    // std::cout << "begin load json\n";
    setConfigFromJSON(config, tree);
    // std::cout << "config loaded\n";
    setFieldFromJSON(field, tree);
    // std::cout << "field loaded\n";
    setSunray(field, config);
    // std::cout << "sunray set\n";
    setGridFromJSON(field, tree);
    // std::cout << "grid set\n";
}

// void SceneLoader::setConfigFromJSON(std::shared_ptr<SceneConfiguration> &config, pt::ptree tree)
// {
//     pt::ptree simu_tree = tree.get_child("simulation");
//     auto num_sunshape_groups = simu_tree.get<int>("num_sunshape_groups");
//     config->setNum_sunshape_groups(num_sunshape_groups);
//     auto num_sunshape_lights_per_group = simu_tree.get<int>("num_sunshape_lights_per_group");
//     config->setNum_sunshape_lights_per_group(num_sunshape_lights_per_group);
//     auto inverse_transform_sampling_groups =
//     simu_tree.get<int>("inverse_transform_sampling_groups");
//     config->setInverse_transform_sampling_groups(inverse_transform_sampling_groups);
//     auto receiver_pixel_length = simu_tree.get<float>("receiver_pixel_length");
//     config->setReceiver_pixel_length(receiver_pixel_length);
//     auto helio_pixel_length = simu_tree.get<float>("heliostat_pixel_length");
//     config->setHelio_pixel_length(helio_pixel_length);

//     pt::ptree config_tree = tree.get_child("config");
//     float azimuth = config_tree.get<float>("sun.sun_position.azimuth");
//     config->setSunAzimuth(azimuth);
//     float elevation = config_tree.get<float>("sun.sun_position.elevation");
//     config->setSunAltitude(elevation);
//     float dni = config_tree.get<float>("sun.sun_position.dni");
//     config->setDni(dni);
//     float csr = config_tree.get<float>("sun.sun_shape.csr");
//     config->setCsr(csr);

//     /**
//      * TODO:: other properties in simu_tree and config_tree are supposed to be treated.
//     */

// }
void SceneLoader::setFieldFromJSON(std::shared_ptr<SceneField>& field, pt::ptree tree)
{
    pt::ptree receiver_tree = tree.get_child("field.receivers");
    setReceiverFromJSON(field, receiver_tree);

    pt::ptree helio_tree = tree.get_child("field.heliostats");
    setHeliostatFromJSON(field, helio_tree);
}

void SceneLoader::setReceiverFromJSON(std::shared_ptr<SceneField>& field, pt::ptree tree)
{
    for (auto it = tree.begin(); it != tree.end(); ++it)
    {
        auto child_tree = tree.get_child(it->first);
        auto type = child_tree.get<std::string>("geometry.type");
        std::shared_ptr<CudaReceiver> rev;
        switch (hash(type.c_str()))
        {
        case "rectangle"_hash:
        {
            rev = std::make_shared<CudaRectangleReceiver>();
            break;
        }
        case "cylinder"_hash:
        {
            rev = std::make_shared<CudaCylinderReceiver>();
            break;
        }
        case "refined_rectangle"_hash:
        {
            rev = std::make_shared<CudaRefinedRectangleReceiver>();
            break;
        }
        case "refined_cylinder"_hash:
        {
            rev = std::make_shared<CudaRefinedCylinderReceiver>();
            break;
        }
        }

        for (auto property_it = child_tree.begin(); property_it != child_tree.end(); ++property_it)
        {
            pt::ptree property_tree = child_tree.get_child(property_it->first);
            // setHelioOrReceiverProperty< std::remove_reference_t<  decltype(*(rev.get()))  > >
            //                                         (rev, property_it->first, property_tree);
            setHelioOrReceiverProperty<std::remove_reference_t<decltype(*(rev.get()))>>(
                rev, property_it->first, property_tree);
            // setHelioOrReceiverProperty< CudaReceiver >(rev, property_it->first, property_tree);
        }

        field->addReceiver(rev);
    }
}
void SceneLoader::setHeliostatFromJSON(std::shared_ptr<SceneField>& field, pt::ptree tree)
{
    for (auto it = tree.begin(); it != tree.end(); ++it)
    {
        auto child_tree = tree.get_child(it->first);
        /**
         * 若存在“differ”标签，则按照differ的个数新建helio
         * 若不存在“differ”标签，说明这一group中只有一个helio
         */
        if (child_tree.find("differ") != child_tree.not_found())
        {
            pt::ptree differ_tree = child_tree.get_child("differ");

            for (auto differ_it = differ_tree.begin(); differ_it != differ_tree.end(); ++differ_it)
            {
                std::shared_ptr<CudaHeliostat> helio = std::make_shared<CudaRectangleHelio>();
                auto branch_tree = differ_it->second;
                // std::cout <<"differ_it.second有几个孩子？" << branch_tree.size() << std::endl;
                for (auto property_it = branch_tree.begin(); property_it != branch_tree.end();
                     ++property_it)
                {
                    pt::ptree property_tree = branch_tree.get_child(property_it->first);
                    setHelioOrReceiverProperty<CudaHeliostat>(helio, property_it->first,
                                                              property_tree);
                }
                for (auto property_it = child_tree.begin(); property_it != child_tree.end();
                     ++property_it)
                {
                    if (property_it->first == "differ")
                        continue;
                    pt::ptree property_tree = child_tree.get_child(property_it->first);
                    setHelioOrReceiverProperty<CudaHeliostat>(helio, property_it->first,
                                                              property_tree);
                }

                helio->setShift(0);
                helio->setBelongingGridId(0); // !!!!!belonging_grid_id
                field->addHeliostat(helio);
            }
        }
        else
        {
            std::shared_ptr<CudaHeliostat> helio = std::make_shared<CudaRectangleHelio>();
            for (auto property_it = child_tree.begin(); property_it != child_tree.end();
                 ++property_it)
            {
                pt::ptree property_tree = child_tree.get_child(property_it->first);
                setHelioOrReceiverProperty<CudaHeliostat>(helio, property_it->first, property_tree);
            }
            helio->setBelongingGridId(0); // !!!!!belonging_grid_id
            field->addHeliostat(helio);
        }
    }
}

template <typename T>
void SceneLoader::setHelioOrReceiverProperty(std::shared_ptr<T>& helio_or_rev, std::string property,
                                             pt::ptree tree)
{
    switch (hash(property.c_str()))
    {
    case "position"_hash:
    {
        auto x = tree.get<float>("x");
        auto y = tree.get<float>("y");
        auto z = tree.get<float>("z");
        helio_or_rev->setPosition(float3(x, y, z));
        break;
    }
    case "thickness"_hash:
    {
        auto thickness = tree.get_value<float>();

        if constexpr (std::is_same_v<T, CudaHeliostat>)
        {
            helio_or_rev->setSizeY(thickness);
        }
        break;
    }
    case "gap"_hash:
    {
        auto x = tree.get<float>("x");
        auto y = tree.get<float>("y");
        if constexpr (std::is_same_v<T, CudaHeliostat>)
        {
            helio_or_rev->setGap(float2(x, y));
        }
        break;
    }
    case "subhelio_row_col"_hash:
    {
        int row = tree.get<int>("row");
        int col = tree.get<int>("col");
        if constexpr (std::is_same_v<T, CudaHeliostat>)
        {
            helio_or_rev->setRowAndColumn(int2(row, col));
        }
        break;
    }
    case "geometry"_hash:
    {
        setGeometryProperty<T>(helio_or_rev, tree);
        break;
    }
    case "material"_hash:
    {
        setGeometryProperty<T>(helio_or_rev, tree);
        break;
    }
    case "normal"_hash:
    {
        auto x = tree.get<float>("x");
        auto y = tree.get<float>("y");
        auto z = tree.get<float>("z");
        helio_or_rev->setNormal({x, y, z});
    }
    }
}

template <typename T>
void SceneLoader::setGeometryProperty(std::shared_ptr<T>& helio_or_rev, pt::ptree tree)
{
    auto type = tree.get<std::string>("type");
    switch (hash(type.c_str()))
    {
    case "rectangle"_hash:
    {
        auto x = tree.get<float>("size.x");
        auto y = tree.get<float>("size.y");

        if constexpr (std::is_same_v<T, CudaHeliostat>)
        {
            helio_or_rev->setShift(0);
            helio_or_rev->setSizeX(x);
            helio_or_rev->setSizeZ(y);
        }
        else if constexpr (std::is_same_v<T, CudaReceiver>)
        {
            helio_or_rev->setType(0);
            helio_or_rev->setSurfaceIndex(0);
            // helio_or_rev->setNormal(float3(0, 0, -1));
            helio_or_rev->setSize(float3(x, y, 0));
        }
        else
        {
            std::cout << "ERROR::SceneLoader::setGeometryProperty::Rectangle\n";
        }
        break;
    }
    case "cylinder"_hash:
    {
        float height = tree.get<float>("height");
        float radius = tree.get<float>("radius");

        // std::cout << typeid(T).name() << " " << typeid(CudaReceiver).name() << std::endl;
        bool ret = std::is_convertible_v<T, CudaReceiver>;
        // std::cout << ret << std::endl;
        ret = std::is_same_v<T, CudaReceiver>;
        // std::cout << ret << std::endl;
        if constexpr (std::is_same_v<T, CudaReceiver>)
        {
            helio_or_rev->setType(1);
            helio_or_rev->setSize(float3(radius, height, 0));
        }
        else
        {
            std::cout << "ERROR::SceneLoader::setGeometryProperty::Cylinder\n";
        }
        break;
    }
    case "refined_rectangle"_hash:
    {
        float x = tree.get<float>("size.x");
        float y = tree.get<float>("size.y");
        float tube_radius = tree.get<float>("tube_radius");
        if constexpr (std::is_same_v<T, CudaReceiver>)
        {
            helio_or_rev->setType(2);
            helio_or_rev->setSurfaceIndex(0);
            helio_or_rev->setNormal(float3(0, 0, -1));
            helio_or_rev->setSize(float3(x, y, 0));
            helio_or_rev->setRadius(tube_radius);
        }
        else
        {
            std::cout << "ERROR::SceneLoader::setGeometryProperty::RefinedRectangle\n";
        }
        break;
    }
    case "refined_cylinder"_hash:
    {
        float height = tree.get<float>("height");
        float radius = tree.get<float>("radius");
        int tube = tree.get<int>("tube");
        int panel = tree.get<int>("panel");
        int tube_unit = tree.get<int>("tube_unit");
        float tube_radius = tree.get<float>("tube_radius");

        if constexpr (std::is_same_v<T, CudaReceiver>)
        {
            helio_or_rev->setType(3);
            helio_or_rev->setSize(float3(radius, height, 0));
            helio_or_rev->setTube(tube);
            helio_or_rev->setPanel(panel);
            helio_or_rev->setTubeUnit(tube_unit);
            helio_or_rev->setRadius(tube_radius);
        }
        else
        {
            std::cout << "ERROR::SceneLoader::setGeometryProperty::RefinedCylinder\n";
        }
        break;
    }
    }
}
/**
 * material相关的属性，貌似不存放在helio和rev上，是存到config里的----先放着
 * TODO::add material to somewhere
 */
template <typename T>
void SceneLoader::setMaterialProperty(std::shared_ptr<T>& helio_or_rev, pt::ptree tree)
{
    std::string type = tree.get<std::string>("type");
    switch (hash_(type.c_str()))
    {
    case "reflect"_hash:
    {
        /**
         * TODO:: 目前的算法，其他参数都是默认的，暂时不需要从文件中读取
         */
        auto slope = tree.get<float>("slope");
        auto reflectivity = tree.get<float>("reflectivity");

        if constexpr (std::is_same_v<T, CudaHeliostat>)
        {
            config_->setDisturbStd(slope);
            config_->setReflectedRate(reflectivity);
        }
        else
        {
            std::cout << "ERROR::SceneLoader::setMaterialProperty::Reflect\n";
        }

        break;
    }
    case "refract"_hash:
    {
        /**
         * TODO:: 目前的算法，其他参数都是默认的，暂时不需要从文件中读取
         */
        auto slope = tree.get<float>("slope");
        auto reflectivity = tree.get<float>("reflectivity");
        auto glass_thickness = tree.get<float>("glass_thickness");
        auto glass_refractive_index = tree.get<float>("glass_refractive_index");

        if constexpr (std::is_same_v<T, CudaHeliostat>)
        {
            config_->setDisturbStd(slope);
            config_->setReflectedRate(reflectivity);
            helio_or_rev->setHelioDepth(glass_thickness);
            helio_or_rev->setRefract(glass_refractive_index);
        }

        else
        {
            std::cout << "ERROR::SceneLoader::setMaterialProperty::Refract\n";
        }

        break;
    }
    case "absorb"_hash:
    {
        /**
         * TODO:: 目前的算法，使用了默认的设置，暂时不需要从json中读取
         */

        if constexpr (std::is_same_v<T, CudaReceiver>)
        {
        }
        else
        {
            std::cout << "ERROR::SceneLoader::setMaterialProperty::Absorb\n";
        }

        break;
    }
    }
}

// void SceneLoader::setSunRay(std::shared_ptr<SceneConfiguration> &config,
//                         std::shared_ptr<SceneField> &field)
// {
//     std::shared_ptr<Sunray> sunray = std::make_shared<Sunray>();
//     sunray->setSunDirection(config->getSun_dir());

//     /**
//      * TODO:: add different type of sunshape
//      * */
//     sunray->setCSR(config->getCsr());
//     sunray->setDNI(config->getDni());
//     sunray->setNumOfSunshapeGroups(config->getNum_sunshape_groups());
//     sunray->setNumOfSunshapeLightsPerGroup(config->getNum_sunshape_lights_per_group());
//     sunray->setReflectiveRate(config->getReflected_rate());    //
//     ！！！！！！这里的反射率是sceneconfiguration中默认设置，不是从定日镜上读取的！！！！

//     field->setSunRay(sunray);
// }
// void SceneLoader::setGrid(std::shared_ptr<SceneField>& field, pt::ptree tree)
// {
//     pt::ptree simu_tree = tree.get_child("simulation");
//     // // 整个场景只有一个Grid
//     auto ground_length = simu_tree.get<float>("ground.x");
//     auto ground_width = simu_tree.get<float>("ground.y");
//     field->setGroundLength(ground_length);
//     field->setGroundWidth(ground_width);

//     std::shared_ptr<CudaGrid> grid = std::make_shared<RectangleGrid>();
//     grid->setGridType(0);
//     grid->setBelongingReceiverIndex(0);     //!!!!属于哪个接收器，目前只有一个接收器
//     grid->setStartHeliostatIndex(0);        //!!!!网格内开始
//     的定日镜序号，只有一个网格，网格内有所有的定日镜

//     float pos_x = simu_tree.get<float>("grid.pos.x");
//     float pos_y = simu_tree.get<float>("grid.pos.y");
//     float pos_z = simu_tree.get<float>("grid.pos.z");
//     float size_x = simu_tree.get<float>("grid.size.x");
//     float size_y = simu_tree.get<float>("grid.size.y");
//     float size_z = simu_tree.get<float>("grid.size.z");
//     float interval_x = simu_tree.get<float>("grid.interval.x");
//     float interval_y = simu_tree.get<float>("grid.interval.y");
//     float interval_z = simu_tree.get<float>("grid.interval.z");
//     grid->setPosition(float3(pos_x, pos_y, pos_z));
//     grid->setSize(float3(size_x, size_y, size_z));
//     grid->setInterval(float3(interval_x, interval_y, interval_z));

//     /**
//      *  TODO:: process all kinds of helio
//     */
//     grid->setNumberOfHeliostats(field->getHeliostats().size());     //
//     ！！！！！！！！！！！先放一个定日镜 grid->setHeliostatType(0);           //
//     ！！！！！！！！！！！定日镜类型暂时定为0---目前只有矩形定日镜

//     field->addGrid(grid);
// }

// /**
//  * 用于测试
// */
// void SceneLoader::generateTestFieldConfig()
// {
//     field_1 = std::make_shared<SceneField>();
//     config_1 = std::make_shared<SceneConfiguration>();

//     field_2 = std::make_shared<SceneField>();
//     config_2 = std::make_shared<SceneConfiguration>();

//     readFile(config_1, field_1);

//     readFileNoTemplate(config_2, field_2);

// }

void SceneLoader::setFile(std::string json_file_path) { json_file_path_ = json_file_path; }

void SceneLoader::readFile_Concise(std::shared_ptr<SceneConfiguration>& config,
                                   std::shared_ptr<SceneField>& field)
{
    read_json(config, field, json_file_path_);
    setSunray(field, config);
}

bool SceneLoader::read_json(std::shared_ptr<SceneConfiguration>& config,
                            std::shared_ptr<SceneField>& field, std::string file_path)
{
    std::ifstream ifs(file_path, std::ios_base::in);
    pt::ptree tree;
    pt::read_json(ifs, tree);

    // std::cout << "根节点包含" << tree.size() << "个孩子节点" << std::endl;
    for (pt::ptree::iterator it = tree.begin(); it != tree.end(); ++it)
    {
        // if(it->first == "config")
        // {
        //     pt::ptree config_tree = tree.get_child(it->first);
        //     setConfigFromJSON(config, config_tree);
        // }
        if (it->first == "field")
        {
            pt::ptree field_tree = tree.get_child(it->first);
            setFieldFromJSON_Concise(field, field_tree);
        }
    }
    setConfigFromJSON(config, tree);
    setGridFromJSON(field, tree);
    return true;
}
void SceneLoader::setSunray(std::shared_ptr<SceneField>& field,
                            std::shared_ptr<SceneConfiguration> configu)
{
    std::shared_ptr<CudaSunray> sunray = std::make_shared<CudaSunray>();
    sunray->setSunDirection(configu->getSun_dir());

    /**
     * TODO:: add different type of sunshape
     * */
    sunray->setCSR(configu->getCsr());
    sunray->setDNI(configu->getDni());
    sunray->setNumOfSunshapeGroups(configu->getNum_sunshape_groups());
    sunray->setNumOfSunshapeLightsPerGroup(configu->getNum_sunshape_lights_per_group());
    sunray->setReflectiveRate(
        configu
            ->getReflected_rate()); // ！！！！！！这里的反射率是sceneconfiguration中默认设置，不是从定日镜上读取的！！！！

    field->setSunRay(sunray);
}
void SceneLoader::setGridFromJSON(std::shared_ptr<SceneField>& field, pt::ptree tree)
{
    pt::ptree simu_tree = tree.get_child("simulation");
    // // 整个场景只有一个Grid
    auto ground_length = simu_tree.get<float>("ground.x");
    auto ground_width = simu_tree.get<float>("ground.y");
    field->setGroundLength(ground_length);
    field->setGroundWidth(ground_width);

    std::shared_ptr<CudaGrid> grid = std::make_shared<CudaRectangleGrid>();
    grid->setGridType(0);
    grid->setBelongingReceiverIndex(0); //!!!!属于哪个接收器，目前只有一个接收器
    grid->setStartHeliostatIndex(
        0); //!!!!网格内开始 的定日镜序号，只有一个网格，网格内有所有的定日镜

    float pos_x = simu_tree.get<float>("grid.pos.x");
    float pos_y = simu_tree.get<float>("grid.pos.y");
    float pos_z = simu_tree.get<float>("grid.pos.z");
    float size_x = simu_tree.get<float>("grid.size.x");
    float size_y = simu_tree.get<float>("grid.size.y");
    float size_z = simu_tree.get<float>("grid.size.z");
    float interval_x = simu_tree.get<float>("grid.interval.x");
    float interval_y = simu_tree.get<float>("grid.interval.y");
    float interval_z = simu_tree.get<float>("grid.interval.z");
    grid->setPosition(float3(pos_x, pos_y, pos_z));
    grid->setSize(float3(size_x, size_y, size_z));
    grid->setInterval(float3(interval_x, interval_y, interval_z));

    /**
     *  TODO:: process all kinds of helio
     */
    grid->setNumberOfHeliostats(
        field->getHeliostats().size()); // ！！！！！！！！！！！先放一个定日镜
    grid->setHeliostatType(0); // ！！！！！！！！！！！定日镜类型暂时定为0---目前只有矩形定日镜

    field->addGrid(grid);
}

void SceneLoader::setConfigFromJSON(std::shared_ptr<SceneConfiguration>& config, pt::ptree tree)
{

    // std::cout << "setConfigFromJSON\n";

    pt::ptree simu_tree = tree.get_child("simulation");
    auto num_sunshape_groups = simu_tree.get<int>("num_sunshape_groups");
    config->setNum_sunshape_groups(num_sunshape_groups);
    auto num_sunshape_lights_per_group = simu_tree.get<int>("num_sunshape_lights_per_group");
    config->setNum_sunshape_lights_per_group(num_sunshape_lights_per_group);
    auto inverse_transform_sampling_groups =
        simu_tree.get<int>("inverse_transform_sampling_groups");
    config->setInverse_transform_sampling_groups(inverse_transform_sampling_groups);
    auto receiver_pixel_length = simu_tree.get<float>("receiver_pixel_length");
    config->setReceiver_pixel_length(receiver_pixel_length);
    auto helio_pixel_length = simu_tree.get<float>("heliostat_pixel_length");
    config->setHelio_pixel_length(helio_pixel_length);

    pt::ptree config_tree = tree.get_child("config");
    float azimuth = config_tree.get<float>("sun.sun_position.azimuth");
    config->setSunAzimuth(azimuth);
    float elevation = config_tree.get<float>("sun.sun_position.elevation");
    config->setSunAltitude(elevation);
    float dni = config_tree.get<float>("sun.sun_position.dni");
    config->setDni(dni);
    float csr = config_tree.get<float>("sun.sun_shape.csr");
    config->setCsr(csr);
    // std::cout << "setConfigFromJSON over\n";
}

void SceneLoader::setFieldFromJSON_Concise(std::shared_ptr<SceneField>& field, pt::ptree tree)
{
    // std::cout << "setFieldFromJSON\n";
    pt::ptree receivers_tree = tree.get_child("receivers");
    setReceiverFromJSON_Concise(field, receivers_tree);
    pt::ptree heliostats_tree = tree.get_child("heliostats");
    setHeliostatFromJSON_Concise(field, heliostats_tree);
}
/**
 * 假设receiver只有一个
 * TODO::
 */
void SceneLoader::setReceiverFromJSON_Concise(std::shared_ptr<SceneField>& field, pt::ptree tree)
{
    // for(pt::ptree::iterator it = tree.begin() ; it != tree.end() ; ++it)    // 遍历所有group
    // {
    //     pt::ptree group_tree = tree.get_child(it->first);

    // }
    // std::cout << "setReceiverFromJSON\n";
    std::shared_ptr<CudaReceiver> rev;
    pt::ptree geometry_tree = tree.get_child("group.geometry");
    std::string geometry_type = geometry_tree.get<std::string>("type");

    if (geometry_type == "rectangle")
    {
        // std::cout << "set rev rectangle\n";
        rev = std::make_shared<CudaRectangleReceiver>();
        rev->setType(0);
        rev->setSurfaceIndex(0);
        rev->setNormal(float3(0, 0, -1));
        float size_x = geometry_tree.get<float>("size.x");
        float size_y = geometry_tree.get<float>("size.y");
        rev->setSize(float3(size_x, size_y, 0));
    }
    else if (geometry_type == "cylinder")
    {
        // std::cout << "set rev cylinder\n";
        rev = std::make_shared<CudaCylinderReceiver>();
        rev->setType(1);
        float height = geometry_tree.get<float>("height");
        float radius = geometry_tree.get<float>("radius");
        rev->setSize(float3(radius, height, 0));
    }
    else if (geometry_type == "refined_rectangle")
    {
        rev = std::make_shared<CudaRefinedRectangleReceiver>();
        rev->setType(2);
        rev->setSurfaceIndex(0);
        rev->setNormal(float3(0, 0, -1));
        float size_x = geometry_tree.get<float>("size.x");
        float size_y = geometry_tree.get<float>("size.y");
        rev->setSize(float3(size_x, size_y, 0));
        float tube_radius = geometry_tree.get<float>("tube_radius");
        rev->setRadius(tube_radius);
    }
    else if (geometry_type == "refined_cylinder")
    {
        rev = std::make_shared<CudaRefinedCylinderReceiver>();
        rev->setType(3);
        int tube = geometry_tree.get<int>("tube");
        int panel = geometry_tree.get<int>("panel");
        int tube_unit = geometry_tree.get<int>("tube_unit");
        float tube_radius = geometry_tree.get<float>("tube_radius");
        rev->setTube(tube);
        rev->setPanel(panel);
        rev->setTubeUnit(tube_unit);
        rev->setRadius(tube_radius);
        float height = geometry_tree.get<float>("height");
        float radius = geometry_tree.get<float>("radius");
        rev->setSize(float3(radius, height, 0));
    }

    float pos_x = tree.get<float>("group.position.x");
    float pos_y = tree.get<float>("group.position.y");
    float pos_z = tree.get<float>("group.position.z");
    rev->setPosition(float3(pos_x, pos_y, pos_z));

    field->addReceiver(rev);
}
void SceneLoader::setHeliostatFromJSON_Concise(std::shared_ptr<SceneField>& field, pt::ptree tree)
{
    // std::cout << "setHeliostatFromJSON\n";
    // pt::ptree group_tree = tree.get_child("group");
    for (pt::ptree::iterator it = tree.begin(); it != tree.end(); ++it)
    {
        pt::ptree group_tree = tree.get_child(it->first);

        pt::ptree geometry_tree = group_tree.get_child("geometry");
        std::string geometry_type = geometry_tree.get<std::string>("type");
        float size_x = geometry_tree.get<float>("size.x");
        float size_y = geometry_tree.get<float>("size.y");
        float thickness = group_tree.get<float>("thickness");
        float3 size(size_x, thickness, size_y);
        float gap_x = group_tree.get<float>("gap.x");
        float gap_y = group_tree.get<float>("gap.y");
        int row = group_tree.get<int>("subhelio_row_col.row");
        int col = group_tree.get<int>("subhelio_row_col.col");

        pt::ptree differ_tree = group_tree.get_child("differ");
        for (auto differ_it = differ_tree.begin(); differ_it != differ_tree.end(); ++differ_it)
        {
            float pos_x = differ_it->second.get<float>("position.x");
            float pos_y = differ_it->second.get<float>("position.y");
            float pos_z = differ_it->second.get<float>("position.z");

            std::shared_ptr<CudaHeliostat> helio = std::make_shared<CudaRectangleHelio>();
            helio->setSize(size);
            helio->setGap(float2(gap_x, gap_y));
            helio->setPosition(float3(pos_x, pos_y, pos_z));
            helio->setRowAndColumn(int2(row, col));

            helio->setShift(0);
            helio->setBelongingGridId(0);

            field->addHeliostat(helio);
        }

        // if(group_tree.find("differ") != group_tree.not_found())
        // {
        //     pt::ptree differ_tree = group_tree.get_child("differ");
        //     int helio_num = differ_tree.size();
        //     for(auto differ_it = differ_tree.begin() ; differ_it != differ_tree.end();
        //     ++differ_it)
        //     {

        //     }

        // }
    }
}
